import os
from http import HTTPStatus
from dashscope import Application
from fastapi import APIRouter, Body, Request, Depends
from configs.other_config import CHAT_WITH_OWN_PET_NO_OCCUPATION_APPID, CHAT_WITH_OWN_PET_WITH_OCCUPATION_APPID, DASHSCOPE_API_KEY, TRAIN_SUMMARY_APPID, ALGORITHM, MARSX_INTENT_RECOGNITION_APPID, INSTRUCTIONS
from configs.kb_config import GO_SERVICE_SECRET_KEY, ENVIRONMENT
from configs.logging_config import configure_logging
from server.db.models.message_model import MarsXChatWithOwnPetSession, MarsXTrainModeSession
from server.db.models.memory_model import Memory, MemoryNode
from server.db.models.pet_kb_model import PetKnowledgeBase
from typing import Optional, Union, Generator
from dashscope.app.application import ApplicationResponse
from server.utils import create_chat_response, BaseResponse, decode_verify_token, create_chat_response_event
from server.bailian.memory_client import client as memory_client
import json
from loguru import logger
from sse_starlette.sse import EventSourceResponse
from server.db.session import get_db
from sqlalchemy.orm import Session
from sqlalchemy import and_
from datetime import datetime, timedelta
import pytz
import asyncio
from configs.other_config import STREAM_RETURN_INTERVAL

configure_logging()
router = APIRouter()

@router.post("/bailian/v1/chat/chat_with_own_pet")
async def chat_with_own_pet_v1(uid: str = Body(..., embed=True, description="用户ID"), 
                            conversation_id: Optional[str] = Body(None, embed=True, description="会话ID"),
                            stream: bool = Body(True, embed=True, description="是否流式输出"),
                            nickname: str = Body(..., embed=True, description="昵称"),
                            character: str = Body(..., embed=True, description="性格"),
                            query: str = Body(..., embed=True, description="用户输入"),
                            pet_query: Optional[str] = Body(None, embed=True, description="宠物输入"),
                            occupation: str = Body(None, embed=True, description="职业"),
                            whether_train: bool = Body(False, embed=True, description="是否训练"),
                            use_knowledge_base: bool = Body(False, embed=True, description="是否使用专属知识库模式"),
                            request: Request = None,
                            db: Session = Depends(get_db)):
    
    # 解码token
    try:
        token = decode_verify_token(request, GO_SERVICE_SECRET_KEY, ALGORITHM)
    except Exception as e:
        return BaseResponse(code=401, msg="Token is invalid", data={"error": str(e.detail.get('msg'))})
    
    memory_object = db.query(Memory).filter(Memory.user_id == uid, Memory.memory_id != "").first()
    if memory_object is not None:
        memory_id = memory_object.memory_id
    else:
        memory = memory_client.create_memory(description=f"MarsXAPP_{ENVIRONMENT}_{uid}")
        memory_id = memory["memoryId"]
        request_id = memory["requestId"]
        memory_object = Memory(
            user_id=uid,
            memory_id=memory_id,
            workspace_id=memory_client.config.workspace_id,
            request_type=0,
            request_id=request_id
        )
        try:
            db.add(memory_object)
            db.commit()
        except Exception as e:
            db.rollback()
            logger.error(f"创建记忆体时数据库操作失败 用户ID: {uid} | 错误信息: {e}")
            return BaseResponse(
                code=HTTPStatus.INTERNAL_SERVER_ERROR,
                msg="创建记忆体时数据库操作失败",
                data={
                    "error_type": "500",
                    "error_message": str(e),
                    "uid": uid,
                    "memory_id": memory_id,
                    "workspace_id": memory_client.config.workspace_id,
                    "request_type": 0,
                    "request_id": request_id
                }
            )
    
    if whether_train:
        if pet_query != "" and query != "":
            # 训练模式train_type为train
            biz_params = {
                "pet_input": pet_query
            }
            responses = Application.call(
                api_key=os.getenv("DASHSCOPE_API_KEY", DASHSCOPE_API_KEY), 
                app_id=TRAIN_SUMMARY_APPID,
                stream=False,
                biz_params=biz_params,
                prompt=query
            )
            if responses.status_code != HTTPStatus.OK:
                logger.error(f"智能体训练错误信息: {responses.code} | {responses.message} 请求ID: {responses.request_id} 用户ID: {uid} 宠物问题：{pet_query} | 用户输入: {query}")
                return BaseResponse(
                    code=responses.status_code,
                    msg=responses.message,
                    data={
                        "error_type": responses.code,
                        "error_message": responses.message,
                        "uid": uid,
                        "pet_input": pet_query,
                        "user_input": query,
                        "summary": "",
                        "relevant": ""
                    }
                )
            else:
                json_data = json.loads(responses.output.text)
                relevant = json_data["relevant"]
                summary = json_data["summarize"]
                if relevant == "1":
                    marsx_train_mode_session_object = db.query(MarsXTrainModeSession).filter(
                        and_(MarsXTrainModeSession.user_id == uid, MarsXTrainModeSession.pet_input == pet_query, MarsXTrainModeSession.memory_node_id != "")).first()
                    if marsx_train_mode_session_object:
                        # 因为已经存在该条NPC的问题，那么接下来就采用更新的方式
                        request_type = 2
                        memory_node_id = marsx_train_mode_session_object.memory_node_id
                        update_memory_node_response = memory_client.update_memory_node(memory_id=memory_id, memory_node_id=memory_node_id, content=summary)
                        update_memory_node_request_id = update_memory_node_response["requestId"]
                        new_memory_node_object = MemoryNode(
                            user_id=uid,
                            workspace_id=memory_client.config.workspace_id,
                            memory_id=memory_id,
                            memory_node_id=memory_node_id,
                            content=summary,
                            request_type=request_type,
                            request_id=update_memory_node_request_id
                        )
                        try:
                            db.add(new_memory_node_object)
                            db.commit()
                        except Exception as e:
                            db.rollback()
                            logger.error(f"更新记忆片段时数据库操作失败 用户ID: {uid} | 用户输入: {query} | 错误信息: {e}")
                            return BaseResponse(
                                code=HTTPStatus.INTERNAL_SERVER_ERROR,
                                msg="更新记忆片段时数据库操作失败",
                                data={
                                    "error_type": "500",
                                    "error_message": str(e),
                                    "uid": uid,
                                    "pet_input": pet_query,
                                    "user_input": query,
                                    "summary": summary,
                                    "relevant": relevant
                                }
                            )
                        
                    else:
                        memory_node_response = memory_client.create_memory_node(memory_id=memory_id, content=json_data["summarize"])
                        memory_node_id = memory_node_response["memoryNodeId"]
                        new_memory_node_object = MemoryNode(
                            user_id=uid,
                            workspace_id=memory_client.config.workspace_id,
                            memory_id=memory_id,
                            memory_node_id=memory_node_id,
                            content=summary,
                            request_type=1,
                            request_id=memory_node_response["requestId"]
                        )
                        
                        new_marsx_train_mode_session_object = MarsXTrainModeSession(
                            user_id=uid,
                            user_input=query,
                            pet_input=pet_query,
                            memory_node_id=memory_node_id,
                            summary=summary,
                            relevant=relevant,
                            request_id=memory_node_response["requestId"],
                            train_type="train" # 训练模式train_type为train
                        )
                        try:
                            db.add(new_marsx_train_mode_session_object)
                            db.add(new_memory_node_object)
                            db.commit()
                        except Exception as e:
                            db.rollback()
                            logger.error(f"创建记忆片段时数据库操作失败 用户ID: {uid} | 用户输入: {query} | 错误信息: {e}")
                            return BaseResponse(
                                code=HTTPStatus.INTERNAL_SERVER_ERROR,
                                msg="创建记忆片段时数据库操作失败",
                                data={
                                    "error_type": "500",
                                    "error_message": str(e),
                                    "uid": uid,
                                    "pet_input": pet_query,
                                    "user_input": query,
                                    "summary": summary,
                                    "relevant": relevant
                                }
                            )
                return BaseResponse(
                    code=responses.status_code,
                    msg=responses.message,
                    data={
                        "error_type": "",
                        "error_message": "",
                        "uid": uid,
                        "pet_input": pet_query,
                        "user_input": query,
                        "summary": summary, # summarize字段名是在阿里云百炼工作流中自定义的
                        "relevant": relevant # relevant字段名是在阿里云百炼工作流中自定义的
                    }
                )
        else:
            # 爱心模式
            try:
                memory_node_response = memory_client.create_memory_node(memory_id=memory_id, content=query)
                memory_node_id = memory_node_response["memoryNodeId"]
                memory_node_request_id = memory_node_response["requestId"]
            except Exception as e:
                logger.error(f"创建记忆片段错误信息: {e} 用户ID: {uid} | 用户输入: {query}")
                return BaseResponse(
                    code=HTTPStatus.INTERNAL_SERVER_ERROR,
                    msg="创建记忆片段失败",
                    data={
                        "error_type": "500",
                        "error_message": str(e),
                        "uid": uid,
                        "pet_input": "",
                        "user_input": query,
                        "summary": "",
                        "relevant": ""
                    }
                )
            new_memory_node_object = MemoryNode(
                user_id=uid,
                workspace_id=memory_client.config.workspace_id,
                memory_id=memory_id,
                memory_node_id=memory_node_id,
                content=query,
                request_type=1,
                request_id=memory_node_request_id
            )
             
            new_marsx_train_mode_session_object = MarsXTrainModeSession(
                user_id=uid,
                user_input=query,
                pet_input="",
                memory_node_id=memory_node_id,
                summary="",
                relevant="",
                request_id=memory_node_request_id,
                train_type="heart" # 爱心模式train_type为heart
            )   
            try:
                db.add(new_memory_node_object)
                db.add(new_marsx_train_mode_session_object)
                db.commit()
            except Exception as e:
                db.rollback()
                logger.error(f"创建记忆片段时数据库操作失败 用户ID: {uid} | 用户输入: {query} | 错误信息: {e}")
                return BaseResponse(
                    code=HTTPStatus.INTERNAL_SERVER_ERROR,
                    msg="创建记忆片段时数据库操作失败",
                    data={
                        "error_type": "500",
                        "error_message": str(e),
                        "uid": uid,
                        "pet_input": "",
                        "user_input": query,
                        "summary": "",
                        "relevant": ""
                    }
                )
            return BaseResponse(
                code=HTTPStatus.OK,
                msg="success",
                data={
                    "error_type": "",
                    "error_message": "",
                    "uid": uid,
                    "pet_input": "",
                    "user_input": query,
                    "summary": "",
                    "relevant": "1"
                }
            )
    beijing_timezone = pytz.timezone("Asia/Shanghai")
    beijing_time = datetime.now(beijing_timezone)
    beijing_time_str = beijing_time.strftime("%Y-%m-%d %H:%M:%S")
    # 星期几
    weekday = beijing_time.weekday()
    weekday_str = ["一", "二", "三", "四", "五", "六", "日"][weekday]
    
    # 知识库模式检查（知识库模式不使用记忆体）
    pipeline_ids = None
    if use_knowledge_base:
        # 获取用户的宠物知识库
        pet_kb = db.query(PetKnowledgeBase).filter(
            PetKnowledgeBase.user_id == uid
        ).first()
        
        if not pet_kb:
            logger.warning(f"用户 {uid} 请求使用知识库模式，但未找到知识库")
            return BaseResponse(
                code=404,
                msg="未找到宠物专属知识库，请先创建知识库并上传文档",
                data={}
            )
        
        if pet_kb.document_count == 0:
            logger.warning(f"用户 {uid} 的知识库为空")
            return BaseResponse(
                code=400,
                msg="知识库中没有文档，请先上传文档",
                data={}
            )
        
        pipeline_ids = [pet_kb.knowledge_base_id]
        logger.info(f"使用知识库模式 用户ID: {uid} | 知识库ID: {pet_kb.knowledge_base_id}")
    
    """
    与自己宠物对话
    """
    if not occupation:
        biz_params = {
            "user_prompt_params": {
                "nickname": nickname,
                "character": character,
                "time": beijing_time_str + " 星期" + weekday_str
            }
        }
        app_id = CHAT_WITH_OWN_PET_NO_OCCUPATION_APPID
    else:
        biz_params = {
            "user_prompt_params": {
                "nickname": nickname,
                "character": character,
                "occupation": occupation,
                "time": beijing_time_str + " 星期" + weekday_str
            }
        }
        app_id = CHAT_WITH_OWN_PET_WITH_OCCUPATION_APPID
    

    # 获取该用户的最新会话（按创建时间倒序）
    session_object = db.query(MarsXChatWithOwnPetSession).filter(
        and_(MarsXChatWithOwnPetSession.user_id == uid, 
             MarsXChatWithOwnPetSession.conversation_id != "")
        ).order_by(MarsXChatWithOwnPetSession.created_time.desc()).first()
    
    # 获取会话的首次创建时间（需要查询同会话ID的最早记录）
    first_created_time = None
    if session_object:
        first_session = db.query(MarsXChatWithOwnPetSession).filter(
            MarsXChatWithOwnPetSession.conversation_id == session_object.conversation_id
        ).order_by(MarsXChatWithOwnPetSession.created_time.asc()).first()
        first_created_time = first_session.created_time if first_session else None 
    # 双重时间校验
    valid_session = False
    if session_object and first_created_time:
        last_active_expired = datetime.now() - session_object.created_time > timedelta(minutes=10)
        first_create_expired = datetime.now() - first_created_time > timedelta(minutes=50)
        # 当检测到会话过期时，则重置会话ID（保留历史记录），并生成新会话ID（由阿里云API返回）
        if not last_active_expired and not first_create_expired:
            valid_session = True
            conversation_id = session_object.conversation_id
        else:
            # 仅重置会话ID（保留历史记录）
            # 生成新会话ID（由阿里云API返回）
            conversation_id = None  
            
            # 可选：标记旧会话为已过期
            db.query(MarsXChatWithOwnPetSession).filter(
                MarsXChatWithOwnPetSession.conversation_id == session_object.conversation_id
            ).update({"is_expired": True})
            db.commit()
    else:
        conversation_id = None

    request_id = None
    try:
        intent_recognition_response = Application.call(
            api_key=os.getenv("DASHSCOPE_API_KEY", DASHSCOPE_API_KEY),
            app_id=MARSX_INTENT_RECOGNITION_APPID,
            prompt=query
        )
        if intent_recognition_response.status_code != HTTPStatus.OK:
            logger.warning(f"意图识别失败状态码: {intent_recognition_response.status_code} 状态码信息: {intent_recognition_response.message}")
            instruction = "-1"
        else:
            intent_recognition_result = intent_recognition_response.output.text
            instruction = json.loads(intent_recognition_result)["intent"]
        request_id = intent_recognition_response.request_id
        code = intent_recognition_response.status_code
    except Exception as e:
        logger.error(f"意图识别失败错误信息: {e}")
        return EventSourceResponse(
            create_chat_response_event(
                response_text=None,
                instruction="-1",
                request_id=request_id,
                finish=True,
                code=500,
                data_content={
                    "error_type": "500",
                    "error_message": str(e)
                }
            )
        )
    
    if instruction in INSTRUCTIONS:
        return EventSourceResponse(
            create_chat_response_event(
                response_text=None,
                instruction=instruction,
                request_id=request_id,
                finish=True,
                code=code,
                data_content={}
            )
        )
    
    # 只有当有有效会话时才传递session_id
    call_params = {
        "api_key": os.getenv("DASHSCOPE_API_KEY", DASHSCOPE_API_KEY),
        "app_id": app_id,
        "prompt": query,
        "stream": True,
        "incremental_output": True,
        "biz_params": biz_params
    }
    
    # 知识库模式：使用知识库，不使用记忆体
    if use_knowledge_base and pipeline_ids:
        call_params["rag_options"] = {"pipeline_ids": pipeline_ids}
        logger.info(f"知识库模式调用 用户ID: {uid} | 知识库ID: {pipeline_ids}")
    else:
        # 记忆体模式：使用记忆体，不使用知识库
        call_params["memory_id"] = memory_id
        logger.info(f"记忆体模式调用 用户ID: {uid} | 记忆体ID: {memory_id}")
    
    if valid_session:
        call_params["session_id"] = conversation_id

    responses = Application.call(**call_params)
    async def event_generator(responses: Union[ApplicationResponse, Generator[ApplicationResponse, None, None]]):
        full_answer = ""
        session_id = None
        request_id = None
        code = None
        for response in responses:
            # response.output.session_id # 会话ID
            if response.status_code != HTTPStatus.OK:
                request_id = response.request_id
                code = response.status_code
                session_id = ""
                session_object = MarsXChatWithOwnPetSession(
                    user_id=uid,
                    conversation_id=session_id,
                    request_id=request_id,
                    user_input=query
                )
                try:
                    db.add(session_object)
                    db.commit()
                except Exception as e:
                    db.rollback()
                    logger.error(f"创建会话时数据库操作失败 用户ID: {uid} | 用户输入: {query} | 错误信息: {e}")
                logger.error(f"错误信息: {response.code} | {response.message} 请求ID: {request_id} 用户ID: {uid} 会话ID: {session_id} 用户输入: {query}")
                await asyncio.sleep(STREAM_RETURN_INTERVAL)
                yield create_chat_response(
                    response_text=None,
                    instruction="-1",
                    request_id=request_id,
                    finish=True,
                    code=code,
                    data_content={
                        "error_type": response.code,
                        "error_message": response.message
                    }
                )
                return
            else:
                if stream:
                    answer = response.output.text
                    full_answer += answer
                    request_id = response.request_id
                    code = response.status_code

                    # 新增：返回时间
                    beijing_timezone = pytz.timezone("Asia/Shanghai")
                    current_time = datetime.now(beijing_timezone).strftime("%Y-%m-%d %H:%M:%S")

                    await asyncio.sleep(STREAM_RETURN_INTERVAL)
                    yield create_chat_response(
                        response_text=answer,
                        instruction="-1",
                        request_id=request_id,
                        finish=False,
                        code=code,
                        data_content={
                            "time": current_time
                        }
                    )
            session_id = response.output.session_id
        session_object = MarsXChatWithOwnPetSession(
            user_id=uid,
            conversation_id=session_id,
            request_id=request_id,
            user_input=query,
            assistant_answer=full_answer
        )
        try:
            db.add(session_object)
            db.commit()
        except Exception as e:
            db.rollback()
            logger.error(f"创建会话时数据库操作失败 用户ID: {uid} | 用户输入: {query} | 错误信息: {e}")
        logger.info(f"用户{uid}的会话ID为{session_id} | 用户输入为：{query} | 智能体回答为：{full_answer}")
        await asyncio.sleep(STREAM_RETURN_INTERVAL)
        yield create_chat_response(
            response_text=full_answer,
            instruction="-1",
            request_id=request_id,
            finish=True,
            code=code,
            data_content={
                "time": current_time
            }
        )
    return EventSourceResponse(event_generator(responses))